#!/bin/python3

# -*- coding:utf-8 -*-
import ldap3
import logging
from Crypto.Hash import MD4

from ldap3 import (
    HASHED_SALTED_SHA, MODIFY_REPLACE
)
import json
from Scripts.headers import config, log_format
from ldap3.utils.hashed import hashed

server = ldap3.Server(host=config.get('ldap', "ip"), port=int(config.get('ldap', "port")), get_info='ALL')
conn = ldap3.Connection(server, config.get("ldap", "admin_cn"), config.get("ldap", "admin_password"))
logging.basicConfig(level=logging.WARNING,
                    format=log_format)


class LdapAction:
    def __init__(self, user_id, password, user_json):
        self.user_id = user_id
        self.password = password
        self.base_cn = config["ldap"]['base_cn']
        self.user_json = user_json
        global conn
        conn.bind()

    # 新创建带有sambaSamAccount账户
    def create_user(self):

        base = {
                    'objectclass': ['inetOrgPerson', 'sambaSamAccount'],
                    'cn': self.user_json['name_pinyin'],
                    'sn': self.user_json['name_pinyin'],
                    'displayName': self.user_json['en_name'],
                    'givenName': self.user_json['name_pinyin'],
                    'uid': self.user_id,
                    'userpassword': self.user_password_get(),
                    'sambaSID': self.user_json['name_pinyin'],
                    'sambaNTPassword': self.samba_password(),
                    'employeeType': self.user_json['employeeType'],
                    'employeeNumber': self.user_json['employeeNumber']
                }

        conn.add(dn=self.who_is(), attributes=base)
        logging.warning(f'创建ldap新用户结果：{conn.result}')

    # 返回sambaNTPassword utf-8 ==>utf-16le
    def samba_password(self):
        h = MD4.new()

        # utf-16le ==>MD4
        h.update(self.password.encode('UTF-16LE'))
        return h.hexdigest().upper()

    # 返回user_password
    def user_password_get(self):
        return hashed(HASHED_SALTED_SHA, self.password)

    # 根据user_name的拼音返回完整的dn
    def who_is(self):
        return 'cn={},{}'.format(self.user_json['name_pinyin'], self.base_cn)

    # 修改user_name修改对应用户的user_password
    def change_ldap_password(self, have_samba, type_action=None, disable=None):
        change_dir = {'userPassword': [(MODIFY_REPLACE, [self.user_password_get()])]}
        if have_samba:
            change_dir['sambaNTPassword'] = [(MODIFY_REPLACE, [self.samba_password()])]
        if disable:
            # 1为已激活，0为未激活
            change_dir['employeeNumber'] = [(MODIFY_REPLACE, ["0"])]
        if self.search_ldap():
            conn.modify(dn=self.search_ldap(), changes=change_dir)
            if conn.result['result'] != 0:
                self.ldap_samba(comm_type="MODIFY_ADD")
                self.change_ldap_password(have_samba=True)
        elif self.search_ldap() is False and type_action:
            self.create_user()
        logging.warning(f'修改用户密码结果为：{conn.result}')

    # 增加、删除samba相关属性
    def ldap_samba(self, comm_type):
        change_dir = {
                        'uid': [(comm_type, self.user_id)],
                        'objectclass': [(comm_type, 'sambaSamAccount')],
                        'sambaSID': [(comm_type, self.user_json['name_pinyin'])],
                        'sambaNTPassword': [(comm_type, self.samba_password())],
                        'employeeType': [(comm_type, self.user_json['employee_type'])],
                        'employeeNumber': [(comm_type, self.user_json['employeeNumber'])]
                      }

        modify_user = self.search_ldap()
        if modify_user:
            conn.modify(dn=modify_user, changes=change_dir)
            result_conn = conn.result
            if result_conn['result'] != 0:
                del change_dir['uid']
                conn.modify(dn=modify_user, changes=change_dir)
            logging.warning(f'增加或者删除samba相关属性的结果为：{conn.result}')
        else:
            logging.warning(f'ldap查找相关用户的结果为：{modify_user}')

    def search_ldap(self):
        conn.search(search_base=self.base_cn, search_filter="(cn={})".format(self.user_json['name_pinyin']))
        # conn.search(search_base=self.base_cn,search_filter="(employeeNumber=1)", attributes=['cn','employeeType',
        # 'uid'])
        try:
            re_json = json.loads(conn.entries[0].entry_to_json())
            return re_json['dn']
        except Exception as e1:
            logging.warning(f'{e1}')
            return False

    def search_ldap_userid(self):
        conn.search(search_base=self.base_cn,
                    search_filter="(&(uid={})(cn={})(sn={}))".format(self.user_json['user_id'],
                                                                     self.user_json['name_pinyin'],
                                                                     self.user_json['en_name']),
                    attributes=['employeeType'])
        try:
            re_json = json.loads(conn.entries[0].entry_to_json())
            return re_json['dn']
        except Exception as e2:
            logging.warning(f'{e2}')
            return False


conn.unbind()
